1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 import java.lang.ref.ReferenceQueue;
35 import java.lang.ref.WeakReference;
36 import java.io.File;
37 import java.io.FileOutputStream;
38 import java.io.InputStream;
39 import java.util.Enumeration;
40 import java.util.HashSet;
41 import java.util.Random;
42 import java.util.Set;
43 import java.util.zip.ZipEntry;
44 import java.util.zip.ZipFile;
45 import java.util.zip.ZipOutputStream;
46
47 public class ClearStaleZipFileInputStreams {
48 private static final int ZIP_ENTRY_NUM = 5;
49
50 private static final byte[][] data;
51
52 static {
53 data = new byte[ZIP_ENTRY_NUM][];
54 Random r = new Random();
55 for (int i = 0; i < ZIP_ENTRY_NUM; i++) {
56 data[i] = new byte[1000];
57 r.nextBytes(data[i]);
58 }
59 }
60
61 private static File createTestFile(int compression) throws Exception {
62 File tempZipFile =
63 File.createTempFile("test-data" + compression, ".zip");
64 tempZipFile.deleteOnExit();
65
66 ZipOutputStream zos =
67 new ZipOutputStream(new FileOutputStream(tempZipFile));
68 zos.setLevel(compression);
69
70 try {
71 for (int i = 0; i < ZIP_ENTRY_NUM; i++) {
72 String text = "Entry" + i;
73 ZipEntry entry = new ZipEntry(text);
74 zos.putNextEntry(entry);
75 try {
76 zos.write(data[i], 0, data[i].length);
77 } finally {
78 zos.closeEntry();
79 }
80 }
81 } finally {
82 zos.close();
83 }
84
85 return tempZipFile;
86 }
87
88 private static void startGcInducingThread(final int sleepMillis) {
89 final Thread gcInducingThread = new Thread() {
90 public void run() {
91 while (true) {
92 System.gc();
93 try {
94 Thread.sleep(sleepMillis);
95 } catch (InterruptedException e) { }
96 }
97 }
98 };
99
100 gcInducingThread.setDaemon(true);
101 gcInducingThread.start();
102 }
103
104 public static void main(String[] args) throws Exception {
105 startGcInducingThread(500);
106 runTest(ZipOutputStream.DEFLATED);
107 runTest(ZipOutputStream.STORED);
108 }
109
110 private static void runTest(int compression) throws Exception {
111 ReferenceQueue<InputStream> rq = new ReferenceQueue<>();
112
113 System.out.println("Testing with a zip file with compression level = "
114 + compression);
115 File f = createTestFile(compression);
116 try {
117 ZipFile zf = new ZipFile(f);
118 try {
119 Set<Object> refSet = createTransientInputStreams(zf, rq);
120
121 System.out.println("Waiting for 'stale' input streams from ZipFile to be GC'd ...");
122 System.out.println("(The test will hang on failure)");
123 while (false == refSet.isEmpty()) {
124 refSet.remove(rq.remove());
125 }
126 System.out.println("Test PASSED.");
127 System.out.println();
128 } finally {
129 zf.close();
130 }
131 } finally {
132 f.delete();
133 }
134 }
135
136 private static Set<Object> createTransientInputStreams(ZipFile zf,
137 ReferenceQueue<InputStream> rq) throws Exception {
138 Enumeration<? extends ZipEntry> zfe = zf.entries();
139 Set<Object> refSet = new HashSet<>();
140
141 while (zfe.hasMoreElements()) {
142 InputStream is = zf.getInputStream(zfe.nextElement());
143 refSet.add(new WeakReference<InputStream>(is, rq));
144 }
145
146 return refSet;
147 }
148 }